package com.ias.redis.serializer;

import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * 支持压缩的Redis序列化器
 *
 * @author IAS Team
 * @version 2.0.0
 */
public class CompressedRedisSerializer implements RedisSerializer<Object> {

    private final RedisSerializer<Object> delegate;
    private final int threshold;
    private static final byte COMPRESSED_FLAG = 1;
    private static final byte UNCOMPRESSED_FLAG = 0;

    public CompressedRedisSerializer(RedisSerializer<Object> delegate, int threshold) {
        this.delegate = delegate;
        this.threshold = threshold;
    }

    @Override
    public byte[] serialize(Object t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }

        byte[] serialized = delegate.serialize(t);
        if (serialized == null || serialized.length < threshold) {
            // 不压缩，添加未压缩标志
            byte[] result = new byte[serialized.length + 1];
            result[0] = UNCOMPRESSED_FLAG;
            System.arraycopy(serialized, 0, result, 1, serialized.length);
            return result;
        }

        try {
            // 压缩数据
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try (GZIPOutputStream gzipOut = new GZIPOutputStream(baos)) {
                gzipOut.write(serialized);
            }
            
            byte[] compressed = baos.toByteArray();
            byte[] result = new byte[compressed.length + 1];
            result[0] = COMPRESSED_FLAG;
            System.arraycopy(compressed, 0, result, 1, compressed.length);
            return result;
        } catch (IOException e) {
            throw new SerializationException("Failed to compress data", e);
        }
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }

        if (bytes.length < 1) {
            throw new SerializationException("Invalid compressed data");
        }

        byte flag = bytes[0];
        byte[] data = new byte[bytes.length - 1];
        System.arraycopy(bytes, 1, data, 0, data.length);

        if (flag == UNCOMPRESSED_FLAG) {
            // 未压缩数据
            return delegate.deserialize(data);
        } else if (flag == COMPRESSED_FLAG) {
            // 解压数据
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                try (GZIPInputStream gzipIn = new GZIPInputStream(new ByteArrayInputStream(data))) {
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = gzipIn.read(buffer)) != -1) {
                        baos.write(buffer, 0, len);
                    }
                }
                return delegate.deserialize(baos.toByteArray());
            } catch (IOException e) {
                throw new SerializationException("Failed to decompress data", e);
            }
        } else {
            throw new SerializationException("Unknown compression flag: " + flag);
        }
    }
} 